﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;
using System.IO;
namespace MDS
{

    public abstract class RaptorSnapshotRepositoryBase
    {

        protected static Dictionary<string, RaptorSnapshotRepositoryBase> _allInstances = new Dictionary<string, RaptorSnapshotRepositoryBase>(StringComparer.OrdinalIgnoreCase);
    
    }

    public class RaptorSnapshotRepository<T> :RaptorSnapshotRepositoryBase, ISnapshotRepository<T> where T : Protocol.IMessage
    {
        private RaptorDB.RaptorDB<string> _raptorDB;
        private string _dbFileName;
        private object _lockObj = new object();


        private RaptorSnapshotRepository(string dbFileName)
        {
            Contract.Requires(!string.IsNullOrEmpty(dbFileName));
            this._dbFileName = dbFileName;
            _raptorDB = new RaptorDB.RaptorDB<string>(dbFileName, false);
        }

        public static RaptorSnapshotRepository<T> GetInstance(string dbFileName)
        {
            Contract.Requires(!string.IsNullOrEmpty(dbFileName));
            lock (_allInstances)
            {
                if (_allInstances.ContainsKey(dbFileName))
                    return _allInstances[dbFileName] as RaptorSnapshotRepository<T>;
                else
                {
                    RaptorSnapshotRepository<T> newInstance = new RaptorSnapshotRepository<T>(dbFileName);
                    _allInstances[dbFileName] = newInstance;
                    return newInstance;
                }
            }
        }


        public bool SaveSnapshot(IEnumerable<T> messages)
        {
            Contract.Requires(messages != null);
            List<T> msgList = messages.ToList();
            bool succeed = false;
            lock (_lockObj)
            {
                try
                {
                    dynamic msgDynamic;
                    foreach (var msg in msgList)
                    {
                        msgDynamic = msg;
                        this._raptorDB.RemoveKey(msgDynamic.StkID);
                        this._raptorDB.Set(msgDynamic.StkID, MessageSerializer.Serialize(msg));
                    }
                    succeed = true;
                }
                catch (Exception ex)
                {
                    Log.Debug(ex.StackTrace);
                }
            }
            return succeed;
        }

        //TODO:考虑改为使用EnumerateStorageFile方法获取
        public bool LoadSnapshot(out Dictionary<string, T> messages)
        {
            bool succeed = false;
            messages = new Dictionary<string, T>();

            lock (this._lockObj)
            {
                try
                {

                    int count = (int)this._raptorDB.Count();
                    dynamic msgDynamic;
                    for (int i = 0; i < count; i++)
                    {
                        byte[] data = this._raptorDB.FetchRecordBytes(i);
                        Protocol.IMessage msg;
                        bool s = MessageSerializer.TryDeserialize(data, out msg);
                        if (s && msg != null)
                        {
                            msgDynamic = msg;
                            messages[msgDynamic.StkID] = msg;
                        }
                    }
                    succeed = true;
                }
                catch (Exception ex)
                {
                    Log.Debug(ex.StackTrace);
                }
            }

            return succeed;
        }
        public bool LoadSnapshot(out IEnumerable<T> messages)
        {
            Dictionary<string, T> dic;
            bool succeed = LoadSnapshot(out dic);
            if (succeed)
            {
                messages = dic.Values;
            }
            else
                messages = null;
            return succeed;
        }
        public T GetMessageByStkId(string stkId)
        {
            byte[] data;
            bool succeed = false;
            lock (this._lockObj)
            {
                succeed = this._raptorDB.Get(stkId, out data);
            }
            if (succeed)
                return default(T);
            else
            {
                Protocol.IMessage rtn;
                MessageSerializer.TryDeserialize(data, out rtn);
                return (T)rtn;
            }

        }

        public bool TryClearAllData()
        {
            throw new NotImplementedException();
        }






    }

}
